home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / Net / NNTP.php < prev    next >
PHP Script  |  2004-10-01  |  21KB  |  710 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Martin Kaltoft   <martin@nitro.dk>                          |
  17. // |          Tomas V.V.Cox    <cox@idecnet.com>                          |
  18. // |          Heino H. Gehlsen <heino@gehlsen.dk>                         |
  19. // +----------------------------------------------------------------------+
  20. //
  21. // $Id: NNTP.php,v 1.15.2.4 2004/03/10 08:47:13 heino Exp $
  22.  
  23. require_once 'PEAR.php';
  24.  
  25. // Deprecated due to naming
  26. define('PEAR_NNTP_ALL',   0);
  27. define('PEAR_NNTP_NAMES', 1);
  28. define('PEAR_NNTP_LIST',  2);
  29.  
  30. /* NNTP Authentication modes */
  31. define('NET_NNTP_AUTHORIGINAL', 'original');
  32. define('NET_NNTP_AUTHSIMPLE',   'simple');
  33. define('NET_NNTP_AUTHGENERIC',  'generic');
  34.  
  35. // Deprecated due to naming
  36. define('PEAR_NNTP_AUTHORIGINAL', NET_NNTP_AUTHORIGINAL);
  37. define('PEAR_NNTP_AUTHSIMPLE',   NET_NNTP_AUTHSIMPLE);
  38. define('PEAR_NNTP_AUTHGENERIC',  NET_NNTP_AUTHGENERIC);
  39.  
  40. /**
  41.  * The NNTP:: class fetches UseNet news articles acording to the standard
  42.  * based on RFC 1036.
  43.  *
  44.  * @version 0.2.2
  45.  * @author Martin Kaltoft   <martin@nitro.dk>
  46.  * @author Tomas V.V.Cox    <cox@idecnet.com>
  47.  * @author Heino H. Gehlsen <heino@gehlsen.dk>
  48.  */
  49.  
  50. class Net_NNTP extends PEAR
  51. {
  52.  
  53.     var $max = '';
  54.     var $min = '';
  55.     var $user = null;
  56.     var $pass = null;
  57.     var $authmode = null;
  58.  
  59.     /** File pointer of the nntp-connection */
  60.     var $fp = null;
  61.  
  62.     /**
  63.      * Connect to the newsserver
  64.      *
  65.      * @param string $nntpserver The adress of the NNTP-server to connect to.
  66.      * @param int $port (optional) the port-number to connect to, defaults to 119.
  67.      * @param string $user (optional) The user name to authenticate with
  68.      * @param string $pass (optional) The password
  69.      * @param string $authmode (optional) The authentication mode
  70.      * @return mixed True on success or Pear Error object on failure
  71.      * @see Net_Nntp::authenticate()
  72.      * @access public
  73.      */
  74.     function connect($nntpserver,
  75.                      $port = 119,
  76.                      $user = null,
  77.                      $pass = null,
  78.                      $authmode = NET_NNTP_AUTHORIGINAL)
  79.     {
  80.         $fp = @fsockopen($nntpserver, $port, $errno, $errstr, 15);
  81.         if (!is_resource($fp)) {
  82.             return $this->raiseError("Could not connect to NNTP-server $nntpserver");
  83.         }
  84.         socket_set_blocking($fp, true);
  85.         if (!$fp) {
  86.             return $this->raiseError('Not connected');
  87.         }
  88.         $response = fgets($fp, 256);
  89.         if ($this->_debug) {
  90.             print "<< $response\n";
  91.         }
  92.         $this->fp   = $fp;
  93.         $this->user = $user;
  94.         $this->pass = $pass;
  95.         $this->authmode = $authmode;
  96.  
  97.         return true;
  98.     }
  99.  
  100.     /**
  101.      * Connect to the newsserver, and issue a GROUP command
  102.      * Once connection is prepared, we can only fetch articles from one group
  103.      * at a time, to fetch from another group, a new connection has to be made.
  104.      *
  105.      * This is to avoid the GROUP command for every article, as it is very
  106.      * ressource intensive on the newsserver especially when used for
  107.      * groups with many articles.
  108.      *
  109.      * @param string $nntpserver The adress of the NNTP-server to connect to.
  110.      * @param int $port (optional) the port-number to connect to, defaults to 119.
  111.      * @param string $newsgroup The name of the newsgroup to use.
  112.      * @param string $user (optional) The user name to authenticate with
  113.      * @param string $pass (optional) The password
  114.      * @param string $authmode (optional) The authentication mode
  115.      * @return mixed True on success or Pear Error object on failure
  116.      * @see Net_Nntp::authenticate()
  117.      * @access public
  118.      * @deprecated Use connect() instead
  119.      */
  120.     function prepareConnection($nntpserver,
  121.                                 $port = 119,
  122.                                 $newsgroup,
  123.                                 $user = null,
  124.                                 $pass = null,
  125.                                 $authmode = NET_NNTP_AUTHORIGINAL)
  126.     {
  127.         /* connect to the server */
  128.         $err = $this->connect($nntpserver, $port, $user, $pass, $authmode);
  129.         if (PEAR::isError($err)) {
  130.             return $err;
  131.         }
  132.  
  133.         /* issue a GROUP command */
  134.         $r = $this->command("GROUP $newsgroup");
  135.  
  136.         if (PEAR::isError($r) || $this->responseCode($r) > 299) {
  137.             return $this->raiseError($r);
  138.         }
  139.         $response_arr = split(' ', $r);
  140.         $this->max = $response_arr[3];
  141.         $this->min = $response_arr[2];
  142.  
  143.         return true;
  144.     }
  145.  
  146.     /**
  147.     * @deprecated
  148.     */
  149.     function prepare_connection($nntpserver,
  150.                                 $port = 119,
  151.                                 $newsgroup,
  152.                                 $user = null,
  153.                                 $pass = null,
  154.                                 $authmode = NET_NNTP_AUTHORIGINAL)
  155.     {
  156.         return $this->prepareConnection($nntpserver, $port, $newsgroup, $user, $pass, $authmode);
  157.     }
  158.  
  159.     /**
  160.     * Auth process (not yet standarized but used any way)
  161.     * http://www.mibsoftware.com/userkt/nntpext/index.html
  162.     *
  163.     * @param string $user The user name
  164.     * @param string $pass (optional) The password if needed
  165.     * @param string $mode Authinfo form: original, simple, generic
  166.     * @return mixed (bool) true on success or Pear Error obj on fail
  167.     * @access public
  168.     */
  169.     function authenticate($user = null, $pass = null, $mode = NET_NNTP_AUTHORIGINAL)
  170.     {
  171.         if ($user === null) {
  172.             return $this->raiseError('Authentication required but no user supplied');
  173.         }
  174.         switch ($mode) {
  175.             case NET_NNTP_AUTHORIGINAL:
  176.                 /*
  177.                     281 Authentication accepted
  178.                     381 More authentication information required
  179.                     480 Authentication required
  180.                     482 Authentication rejected
  181.                     502 No permission
  182.                 */
  183.                 $response = $this->command("AUTHINFO user $user", false);
  184.                 if ($this->responseCode($response) != 281) {
  185.                     if ($this->responseCode($response) == 381 && $pass !== null) {
  186.                         $response = $this->command("AUTHINFO pass $pass", false);
  187.                     }
  188.                 }
  189.                 if ($this->responseCode($response) != 281) {
  190.                     return $this->raiseError("Authentication failed: $response");
  191.                 }
  192.                 return true;
  193.                 break;
  194.             case NET_NNTP_AUTHSIMPLE:
  195.             case NET_NNTP_AUTHGENERIC:
  196.             default:
  197.                 $this->raiseError("The auth mode: $mode isn't implemented");
  198.         }
  199.     }
  200.  
  201.     /**
  202.      * Get an article from the currently open connection.
  203.      * To get articles from another newsgroup a new prepare_connection() -
  204.      * call has to be made with apropriate parameters
  205.      *
  206.      * @param mixed $article Either the message-id or the message-number on the server of the article to fetch
  207.      * @return string the article
  208.      * @access public
  209.      */
  210.     function getArticle($article)
  211.     {
  212.         /* tell the newsserver we want an article */
  213.         $r = $this->command("ARTICLE $article");
  214.         if (PEAR::isError($r) || $this->responseCode($r) > 299) {
  215.             return $this->raiseError($r);
  216.         }
  217.         $post = null;
  218.         while (!feof($this->fp)) {
  219.             $line = rtrim(fgets($this->fp, 256), "\r\n");
  220.  
  221.             if ($line == ".") {
  222.                 break;
  223.             } else {
  224.                 $post .= $line ."\n";
  225.             }
  226.         }
  227.         return $post;
  228.     }
  229.  
  230.     /**
  231.     * @deprecated
  232.     */
  233.     function get_article($article)
  234.     {
  235.         return $this->getArticle($article);
  236.     }
  237.  
  238.     /**
  239.      * Post an article to a newsgroup.
  240.      * Among the aditional headers you might think of adding could be:
  241.      * "NNTP-Posting-Host: <ip-of-author>", which should contain the IP-adress
  242.      * of the author of the post, so the message can be traced back to him.
  243.      * Or "Organization: <org>" which contain the name of the organization
  244.      * the post originates from.
  245.      *
  246.      * @param string $subject The subject of the post.
  247.      * @param string $newsgroup The newsgroup to post to.
  248.      * @param string $from Name + email-adress of sender.
  249.      * @param string $body The body of the post itself.
  250.      * @param string $aditionak (optional) Aditional headers to send.
  251.      * @return string server response
  252.      * @access public
  253.      */
  254.     function post($subject, $newsgroup, $from, $body, $aditional = "")
  255.     {
  256.         if (!@is_resource($this->fp)) {
  257.             return $this->raiseError('Not connected');
  258.         }
  259.  
  260.         /* tell the newsserver we want to post an article */
  261.         $r = $this->command('POST');
  262.         if (PEAR::isError($r) || $this->responseCode($r) != 340) {
  263.             return $this->raiseError($r);
  264.         }
  265.  
  266.         $data = '';
  267.         $data .= "From: $from\r\n";
  268.         $data .= "Newsgroups: $newsgroup\r\n";
  269.         $data .= "Subject: $subject\r\n";
  270.         $data .= "X-poster: PEAR::Net_NNTP (0.2)\r\n";
  271.         if (!empty($aditional)) {
  272.             $data .= rtrim($aditional, "\r\n")."\r\n";
  273.         }
  274.         $data .= "\r\n";
  275.         $data .= "$body\r\n";
  276.         $data .= ".";
  277.  
  278.         return $this->command($data, false);
  279.     }
  280.  
  281.  
  282.     /**
  283.      * Get the headers of an article from the currently open connection
  284.      * To get the headers of an article from another newsgroup, a new
  285.      * prepare_connection()-call has to be made with apropriate parameters
  286.      *
  287.      * @param string $article Either a message-id or a message-number of the article to fetch the headers from.
  288.      * @return array Header
  289.      * @access public
  290.      */
  291.     function getHeaders($article)
  292.     {
  293.         /* tell the newsserver we want an article */
  294.         $r = $this->command("HEAD $article");
  295.         if (PEAR::isError($r) || $this->responseCode($r) > 299) {
  296.             return $this->raiseError($r);
  297.         }
  298.  
  299.         $headers = '';
  300.         while(!feof($this->fp)) {
  301.             $line = rtrim(fgets($this->fp, 256), "\r\n");
  302.  
  303.             if ($line == '.') {
  304.                 break;
  305.             } else {
  306.                 $headers .= $line . "\n";
  307.             }
  308.         }
  309.         return $headers;
  310.     }
  311.  
  312.     /**
  313.     * @deprecated
  314.     */
  315.     function get_headers($article)
  316.     {
  317.         return $this->getHeaders($article);
  318.     }
  319.  
  320.     /**
  321.     * Returns the headers of a given article in the form of
  322.     * an associative array. Ex:
  323.     * array(
  324.     *   'From'      => 'foo@bar.com (Foo Smith)',
  325.     *   'Subject'   => 'Re: Using NNTP class',
  326.     *   ....
  327.     *   );
  328.     *
  329.     * @param $article string Article number or id
  330.     * @return array Assoc array with headers names as key or Pear obj error
  331.     * @access public
  332.     */
  333.     function splitHeaders($article)
  334.     {
  335.         $headers = $this->get_headers($article);
  336.         if (PEAR::isError($headers)) {
  337.             return $headers;
  338.         }
  339.  
  340.         $lines = explode("\n", $headers);
  341.         foreach ($lines as $line) {
  342.             $line = trim($line);
  343.             if (($pos = strpos($line, ':')) !== false) {
  344.                 $head = substr($line, 0, $pos);
  345.                 $ret[$head] = ltrim(substr($line, $pos+1));
  346.             // if the field was longer than 256 chars, look also in the next line
  347.             // XXX a better way to discover that than strpos?
  348.             } else {
  349.                 $ret[$head] .= $line;
  350.             }
  351.         }
  352.         if (isset($ret['References']) &&
  353.             preg_match_all('|<.+>|U', $ret['References'], $matches))
  354.         {
  355.             $ret['References'] = $matches[0];
  356.         }
  357.         return $ret;
  358.     }
  359.  
  360.     /**
  361.     * @deprecated
  362.     */
  363.     function split_headers($article) {
  364.         return $this->splitHeaders($article);
  365.     }
  366.  
  367.     /**
  368.      * Get the body of an article from the currently open connection.
  369.      * To get the body of an article from another newsgroup, a new
  370.      * prepare_connection()-call has to be made with apropriate parameters
  371.      *
  372.      * @param string $article Either a message-id or a message-number of the article to fetch the headers from.
  373.      * @access public
  374.      */
  375.     function getBody($article)
  376.     {
  377.         /* tell the newsserver we want an article */
  378.         $r = $this->command("BODY $article");
  379.         if (PEAR::isError($r) || $this->responseCode($r) > 299) {
  380.             return $this->raiseError($r);
  381.         }
  382.  
  383.         $body = null;
  384.         while (!feof($this->fp)) {
  385.             $line = rtrim(fgets($this->fp, 256), "\r\n");
  386.  
  387.             if ($line == '.') {
  388.                 break;
  389.             } else {
  390.                 $body .= $line ."\n";
  391.             }
  392.         }
  393.         return $body;
  394.     }
  395.  
  396.     /**
  397.     * @deprecated
  398.     */
  399.     function get_body($article) {
  400.         return $this->getBody($article);
  401.     }
  402.  
  403.     /**
  404.      * Get data until a line with only a '.' in it is read and return data.
  405.      *
  406.      * @return string data
  407.      * @access private
  408.      * @author Morgan Christiansson <mog@linux.nu>
  409.      */
  410.     function _getData()
  411.     {
  412.         $body = array();
  413.         while(!feof($this->fp)) {
  414.             $line = rtrim(fgets($this->fp, 256), "\r\n");
  415.             if ($line == '.') {
  416.                 break;
  417.             } else {
  418.                 $body[] = $line;
  419.             }
  420.         }
  421.         return $body;
  422.     }
  423.  
  424.     /**
  425.     * @deprecated
  426.     */
  427.     function get_data() {
  428.         return $this->_getData();
  429.     }
  430.  
  431.     /**
  432.     * Selects a news group (issue a GROUP command to the server)
  433.     *
  434.     * @param string $newsgroup The newsgroup name
  435.     * @return mixed Array on success or Pear Error object on failure
  436.     */
  437.     function selectGroup($newsgroup)
  438.     {
  439.         $r = $this->command("GROUP $newsgroup");
  440.         if (PEAR::isError($r) || $this->responseCode($r) > 299) {
  441.             return $this->raiseError($r);
  442.         }
  443.         $response_arr = split(' ', $r);
  444.         $this->max = $response_arr[3];
  445.         $this->min = $response_arr[2];
  446.  
  447.         return array(
  448.                      "first" => $response_arr[2],
  449.                      "last"  => $response_arr[3]
  450.                     );
  451.     }
  452.  
  453.     /**
  454.     * @deprecated
  455.     */
  456.     function select_group($newsgroup) {
  457.         return $this->selectGroup($newsgroup);
  458.     }
  459.  
  460.     /**
  461.      * Fetches a list of all avaible newsgroups
  462.      *
  463.      * @param int $fetch PEAR_NNTP_ALL PEAR_NNTP_NAMES PEAR_NNTP_LIST
  464.      * @return array nested array with informations about
  465.      *               existing newsgroups
  466.      * @author Morgan Christiansson <mog@linux.nu>
  467.      */
  468.     function getGroups($fetch = true)
  469.     {
  470.         $this->command("LIST");
  471.         foreach($this->_getData() as $line) {
  472.             $arr = explode(" ",$line);
  473.             $groups[$arr[0]]["group"] = $arr[0];
  474.             $groups[$arr[0]]["last"] = $arr[1];
  475.             $groups[$arr[0]]["first"] = $arr[2];
  476.             $groups[$arr[0]]["posting_allowed"] = $arr[3];
  477.         }
  478.  
  479.         $this->command("LIST NEWSGROUPS");
  480.         foreach($this->_getData() as $line) {
  481.             preg_match("/^(.*?)\s(.*?$)/",$line,$matches);
  482.             $groups[$matches[1]]["desc"] = $matches[2];
  483.         }
  484.         return $groups;
  485.     }
  486.  
  487.     /**
  488.     * @deprecated
  489.     */
  490.     function get_groups($fetch=true) {
  491.         return $this->getGroups($fetch);
  492.     }
  493.  
  494.     /**
  495.     * Returns a list of avaible headers
  496.     * which are send from newsserver to client
  497.     * for every news message
  498.     *
  499.     * @return array header names
  500.     * @access public
  501.     */
  502.     function getOverviewFmt()
  503.     {
  504.         $this->command("LIST OVERVIEW.FMT");
  505.         $format = array("number");
  506.         // XXX Use the splitHeaders() algorithm for supporting
  507.         //     multiline headers?
  508.         foreach ($body = $this->_getData() as $line) {
  509.             $line = current(explode(":",$line));
  510.             $format[] = $line;
  511.         }
  512.         return $format;
  513.     }
  514.  
  515.     /**
  516.     * @deprecated
  517.     */
  518.     function get_overview_fmt() {
  519.         return $this->getOverviewFmt();
  520.     }
  521.  
  522.     /**
  523.     * Fetch message header
  524.     * from message number $first until $last
  525.     *
  526.     * The format of the returned array is:
  527.     * $messages[message_id][header_name]
  528.     *
  529.     * @param integer $first first article to fetch
  530.     * @param integer $last  last article to fetch
  531.     * @return array  nested array of message and
  532.     *                there headers
  533.     * @access public
  534.     */
  535.     function getOverview($first,$last) {
  536.         $format = $this->getOverviewFmt();
  537.  
  538.         $this->command("XOVER $first-$last");
  539.         foreach($this->_getData() as $line) {
  540.             $i=0;
  541.             foreach(explode("\t",$line) as $line) {
  542.                 $message[$format[$i++]] = $line;
  543.             }
  544.             $messages[$message["Message-ID"]] = $message;
  545.         }
  546.  
  547.         return $messages;
  548.     }
  549.  
  550.     /**
  551.     * @deprecated
  552.     */
  553.     function get_overview($first,$last) {
  554.         return $this->getOverview($first, $last);
  555.     }
  556.  
  557.     /**
  558.      * Get the date from the newsserver
  559.      * format of returned date:
  560.      * $date['y'] - year
  561.      * $date['m'] - month
  562.      * $date['d'] - day
  563.      *
  564.      * @return array date
  565.      * @access public
  566.      */
  567.     function date()
  568.     {
  569.         $r = $this->command('DATE');
  570.         if (PEAR::isError($r) || $this->responseCode($r) > 299) {
  571.             return $this->raiseError($r);
  572.         }
  573.         $data = explode(' ',$r);
  574.         $date['y']=substr($data[1],0,4);
  575.         $date['m']=substr($data[1],4,2);
  576.         $date['d']=substr($data[1],6,2);
  577.         return $date;
  578.     }
  579.  
  580.     /**
  581.      * Maximum article number in current group
  582.      *
  583.      * @return integer maximum
  584.      * @access public
  585.      */
  586.     function max()
  587.     {
  588.         if (!@is_resource($this->fp)) {
  589.             return $this->raiseError('Not connected');
  590.         }
  591.         return $this->max;
  592.     }
  593.  
  594.     /**
  595.      * Minimum article number in current group
  596.      *
  597.      * @return integer minimum
  598.      * @access public
  599.      */
  600.     function min()
  601.     {
  602.         if (!@is_resource($this->fp)) {
  603.             return $this->raiseError('Not connected');
  604.         }
  605.         return $this->min;
  606.     }
  607.  
  608.     /**
  609.      * Test whether we are connected or not.
  610.      *
  611.      * @return bool true or false
  612.      * @access public
  613.      */
  614.     function isConnected()
  615.     {
  616.         if (@is_resource($this->fp)) {
  617.             return true;
  618.         }
  619.         return false;
  620.     }
  621.  
  622.     /**
  623.     * @deprecated
  624.     */
  625.     function is_connected() {
  626.         return $this->isConnected();
  627.     }
  628.  
  629.     /**
  630.      * Close connection to the newsserver
  631.      *
  632.      * @access public
  633.      */
  634.     function quit()
  635.     {
  636.         $this->command("QUIT");
  637.         fclose($this->fp);
  638.     }
  639.  
  640.     /**
  641.     * returns the response code
  642.     * of a newsserver command
  643.     *
  644.     * @param string $response newsserver answer
  645.     * @return integer response code
  646.     * @access public
  647.     */
  648.     function responseCode($response)
  649.     {
  650.         $parts = explode(' ', ltrim($response));
  651.         return (int) $parts[0];
  652.     }
  653.  
  654.     /**
  655.     * sets debug on or off
  656.     *
  657.     * @param boolean $on true=on, false=off
  658.     * @access public
  659.     */
  660.     function setDebug($on = true)
  661.     {
  662.         $this->_debug = $on;
  663.     }
  664.  
  665.     /**
  666.     * @deprecated
  667.     */
  668.     function set_debug($on = true) {
  669.         return $this->setDebug();
  670.     }
  671.  
  672.     /**
  673.     * Issue a command to the NNTP server
  674.     *
  675.     * @param string $cmd The command to launch, ie: "ARTICLE 1004853"
  676.     * @param bool $testauth Test or not the auth
  677.     * @return mixed True on success or Pear Error object on failure
  678.     * @access public
  679.     */
  680.     function command($cmd, $testauth = true)
  681.     {
  682.         if (!@is_resource($this->fp)) {
  683.             return $this->raiseError('Not connected');
  684.         }
  685.         fputs($this->fp, "$cmd\r\n");
  686.         if ($this->_debug) {
  687.             print ">> $cmd\n";
  688.         }
  689.         $response = fgets($this->fp, 128);
  690.         if ($this->_debug) {
  691.             print "<< $response\n";
  692.         }
  693.         // From the spec: "In all cases, clients must provide
  694.         // this information when requested by the server. Servers are
  695.         // not required to accept authentication information that is
  696.         // volunteered by the client"
  697.         $code = $this->responseCode($response);
  698.         if ($testauth && ($code == 450 || $code == 480)) {
  699.             $error = $this->authenticate($this->user, $this->pass, $this->authmode);
  700.             if (PEAR::isError($error)) {
  701.                 return $error;
  702.             }
  703.             /* re-issue the command */
  704.             $response = $this->command($cmd, false);
  705.         }
  706.         return $response;
  707.     }
  708. }
  709. ?>
  710.